package com.iiitb.wtp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.StringTokenizer;
import java.util.concurrent.CopyOnWriteArrayList;

import org.apache.commons.collections.bag.HashBag;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.impl.client.DefaultHttpClient;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;

import com.iiitb.model.SeedHandler;

public class MarkovSim {

	public void runSimulation(WebGraph wg) throws SQLException,
			ClientProtocolException, IOException {
		SeedHandler db = new SeedHandler();
		Map<Integer, Double> tagSimVector = new HashMap<>();
		Map<String, String> outputTags = new HashMap<>();
		Map<String, String> seedData = new HashMap<String, String>();
		Double combinedScore = 0.0;
		Double sum = 0.0;
		Map<Integer, Map<Integer, Double>> temp = new HashMap<Integer, Map<Integer, Double>>();
		Map<Integer, Double> temp1 = new HashMap<>();

		seedData = db.querySeedData();
		for (Map.Entry<String, String> entry : seedData.entrySet()) {
			String[] multitag = entry.getValue().split(",");
			for (String tag : multitag) {
				System.out.println("Extracting for tag " + tag);
				int mixingTime = 10;
				String[] split = tag.trim().split("\\s+");
				String str = null;
				String inString = "";
				for (String string : split) {
					str = Character.toString(string.charAt(0)).toUpperCase()
							+ string.substring(1);
					str = str + "_";
					inString = inString + str;
				}
				inString = inString.substring(0, inString.length() - 1);
				String url = "http://en.wikipedia.org/wiki/" + inString;
				try {
					URL connect = new URL(url);
					URLConnection yc = connect.openConnection();
				} catch (IOException e) {
					e.printStackTrace();
				}
				System.out.println("tag url " + url);
				String content = getContent(url);
				String webUrl;
				Double docSim;
				DocumentVector tagVector = getdocVector(content);
				DocumentVector webVector;
				for (int i = 0; i < wg.numNodes(); i++) {
					webUrl = wg.IdentifyerToURL(i);
					content = getContent(webUrl);
					webVector = getdocVector(content);
					docSim = getDocSimilarity(webVector, tagVector);
					System.out.println("document sim with tag wiki " + docSim);
					tagSimVector.put(i, docSim);
				}
				
				for (int i = 0; i < wg.numNodes(); i++) {
					for (int k = 0; k < wg.numNodes(); k++) {
						combinedScore = tagSimVector.get(k) * wg.outLink(i, k);
						System.out.println(combinedScore + " combined score");
						sum = sum + combinedScore;
					}
					for (int j = 0; j < wg.numNodes(); j++) {
						combinedScore = tagSimVector.get(j) * wg.outLink(i, j);
						combinedScore = combinedScore / sum;
						System.out.println("combined score "+ combinedScore + " sum " + sum);
						System.out.println("final combined score "
								+ combinedScore);
						temp1.put(j, combinedScore);
						temp.put(i, temp1);
					}

				}
				DocumentVector hitsvector1 = new DocumentVector();
				DocumentVector hitsvector2 = new DocumentVector();
				double stdDist;

				do {
					Map<Integer, Double> temp2 = new HashMap<>();
					ArrayList<Integer> random = new ArrayList<>();
					ArrayList<Integer> hits1 = new ArrayList<>();
					ArrayList<Integer> hits2 = new ArrayList<>();

					// HashBag hits1 = new HashBag();
					// HashBag hits2 = new HashBag();
					int currentNode1 = 0;
					int currentNode2 = 0;
					for (int l = 0; l < 100000; l++) {

						for (int i = 0; i < mixingTime; i++) {
							System.out.println(mixingTime + " mixing time");
							temp2 = temp.get(currentNode1);
							for (int j = 0; j < wg.numNodes(); j++) {
								int randWt = (int) (temp2.get(j) * 1000000);
								for (int k = 0; k < randWt; k++) {
									random.add(j);
								}
							}
							Random rand = new Random();
							int randomNumber = rand.nextInt(random.size());
							// System.out.println("rand " + randomNumber);
							currentNode1 = random.get(randomNumber);
							random.clear();
						}
						hits1.add(currentNode1);

						for (int i = 0; i < mixingTime; i++) {

							temp2 = temp.get(currentNode2);
							for (int j = 0; j < wg.numNodes(); j++) {
								int randWt = (int) (temp2.get(j) * 1000000);
								for (int k = 0; k < randWt; k++) {
									random.add(j);
								}
							}
							Random rand = new Random();
							int randomNumber = rand.nextInt(random.size());
							// System.out.println("rand2 " + randomNumber);
							currentNode2 = random.get(randomNumber);
							random.clear();
						}
						hits2.add(currentNode2);
					}
					hitsvector1.clear();
					hitsvector2.clear();
					for (Integer urlID : hits1) {
						hitsvector1.incCount(urlID.toString());
					}
					for (Integer urlID : hits2) {
						hitsvector2.incCount(urlID.toString());
					}
					stdDist = hitsvector1.getCosineSimilarityWith(hitsvector2);
					System.out.println(stdDist + " standard dist");
					mixingTime = (int) Math.pow(mixingTime, 2.0);
				} while (stdDist < 0.9);
				System.out.println("out of do while");
				int count;
				String tags = "";
				for (Integer i = 0; i < wg.numNodes(); i++) {
					count = hitsvector1.getCount(i.toString());
					if (count > 0.1 * 100000) {
						if (outputTags.containsKey(wg.IdentifyerToURL(i))) {
							tags = outputTags.get(wg.IdentifyerToURL(i)) + ", "
									+ tag;
							outputTags.put(wg.IdentifyerToURL(i), tags);
							db.insertHITSData(wg.IdentifyerToURL(i), tags);
						} else {
							outputTags.put(wg.IdentifyerToURL(i), tag);
							db.insertHITSData(wg.IdentifyerToURL(i), tag);
						}
					}
				}

			}
		}
		db.serializeJavaObjectToFile(outputTags);

	}

	private DocumentVector getdocVector(String content) {
		DocumentVector dv = new DocumentVector();

		try {

			Document doc = Jsoup.parse(content);
			String token = "";
			Elements ele = doc.getElementsByTag("p");
			Document doc1 = Jsoup.parse(ele.toString());

			String body = doc1.body().text();
			StringTokenizer strtok = new StringTokenizer(body);
			Stopwords sw = new Stopwords();
			while (strtok.hasMoreTokens()) {
				token = strtok.nextToken().replaceAll("[^\\p{Alpha}]+", "");

				if (!token.equals("") && !sw.is(token)) {
					token = token.toLowerCase();
					dv.incCount(token);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return dv;
	}

	private String getContent(String url) throws ClientProtocolException,
			IOException {
		String line;
		String sourceLine = null;
		try {
			System.out.println("get content of url " + url);
			HttpHost proxy = new HttpHost("192.168.3.254", 8080, "http");
			HttpClient client = new DefaultHttpClient();
			client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,
					proxy);
			HttpGet get = new HttpGet(url);

			HttpResponse response = client.execute(get);
			InputStreamReader is = new InputStreamReader(response.getEntity()
					.getContent(), "UTF8");
			BufferedReader rd = new BufferedReader(is);

			while ((line = rd.readLine()) != null) {
				sourceLine = sourceLine + line;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return sourceLine;

	}

	public Double getDocSimilarity(DocumentVector webgraphNode,
			DocumentVector tagvector) throws SQLException {

		// System.out.println("Similarity = " + v1.getCosineSimilarityWith(v2));
		return tagvector.getCosineSimilarityWith(webgraphNode);
	}

}
